package com.laolang.thresh.module.auth.handler;

import cn.hutool.json.JSONUtil;
import com.beust.jcommander.internal.Maps;
import com.laolang.thresh.framework.common.core.consts.DefaultStatusCode;
import com.laolang.thresh.framework.common.core.domain.R;
import com.laolang.thresh.framework.common.core.exception.BusinessException;
import com.laolang.thresh.framework.common.util.web.ServletUtil;
import com.laolang.thresh.framework.redis.util.RedisUtil;
import com.laolang.thresh.module.auth.consts.AuthRedisConsts;
import com.laolang.thresh.module.auth.domain.LoginUser;
import com.laolang.thresh.module.auth.propterties.AuthProperties;
import com.laolang.thresh.module.auth.rsp.LoginRsp;
import com.laolang.thresh.module.auth.service.TokenService;
import com.laolang.thresh.module.system.user.business.SysUserLoginLogBusiness;
import com.laolang.thresh.module.system.user.consts.SysUserLoginLogEnums.OpSource;
import com.laolang.thresh.module.system.user.consts.SysUserLoginLogEnums.OpType;
import io.vavr.Tuple2;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

/**
 * xxx.
 *
 * @author laolang
 * @version 0.1
 */
@Slf4j
@RequiredArgsConstructor
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    private final TokenService tokenService;
    private final RedisUtil redisUtil;
    private final AuthProperties authProperties;
    private final SysUserLoginLogBusiness sysUserLoginLogBusiness;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException, ServletException {
        Object principal = authentication.getPrincipal();
        if (!(principal instanceof LoginUser)) {
            log.error("spring security principal 信息不正确");
            throw new BusinessException(DefaultStatusCode.ERROR);
        }
        LoginUser loginUser = (LoginUser) principal;

        // 生成 token
        Map<String, Object> payload = Maps.newHashMap();
        payload.put("id", 1001L);
        payload.put("username", "superAdmin");
        Tuple2<String, String> jwtTuple = tokenService.genJwt(payload, loginUser.getJwtSecret());

        LoginRsp rsp = new LoginRsp();
        rsp.setToken(jwtTuple._1);
        rsp.setUuid(jwtTuple._2);

        // 保存 token 到 redis
        loginUser.setTokenUuid(rsp.getUuid());
        loginUser.setTokenValue(rsp.getToken());
        redisUtil.set(AuthRedisConsts.JWT_PREFIX + rsp.getUuid(), loginUser, authProperties.getAccessExpire() * 60);

        // TODO 保存登录日志 异步
        sysUserLoginLogBusiness.saveLoginLog(loginUser.getId(), OpType.IN, OpSource.USER);

        // 输出登录结果
        ServletUtil.renderJson(response, JSONUtil.toJsonStr(R.ok(rsp)));
    }
}
